Computers perform comparisons of actual or desired events against preprogrammed or stored events during program code execution. The result of the comparison determines flow of program code execution. Such comparisons are performed, for example, by tracing infrastructure used for debugging computer software. Such infrastructure may provide for simultaneous tracing of components within program code to facilitate debugging. A developer of the program code preprograms potential trace events within the program, and a user later determines the trace events desired for logging. A comparison is performed at runtime, comparing preprogrammed trace events against user-desired trace events. When the comparison results in a match, a trace is performed, and when the comparison does not result in a match, a trace is not performed.
It may be desired to perform multiple comparisons at one time to maximize efficiency, minimize CPU burden, and the like. Such parallel comparisons may be useful when program code allows for execution of multiple components simultaneously. For example, in a tracing infrastructure, it may be desired to complete different types of traces simultaneously. One type of trace may be a performance trace, checking the beginning and ending of functions, timing around operations, or parts of code that have been executed multiple times. Another type of trace may be a diagnostic trace, checking within program code for errors at runtime. A third type of trace may be an administrative or operational trace, an external trace for users and administrators that provides tracing similar to diagnostic traces. Each type of trace additionally may include different “levels.” The levels may be inclusive such that each higher level would include all trace levels below it. Therefore, in addition to performing multiple trace types simultaneously, the tracing infrastructure may allow for filtering levels of the traces by comparing developer-configured trace levels with user-desired trace levels. Comparisons at runtime are completed to provide tracing when the configured trace levels and user trace levels overlap and to not provide traces when levels do not overlap.
To perform simultaneous, that is, parallel, comparisons, typical program code for such a tracing infrastructure may look like:
If (((userDiagnosticLevel <= configuredDiagnosticLevel) &&(userDiagnosticLevel != 0)) || ((userPerformanceLevel <= configuredPerformanceLevel) && (userPerformanceLevel != 0))){ // do the trace}
If a single variable that contains both the diagnostics and performance levels is used, the check might look like:
If ((((userLevel & DiagMask) <= (configLevel & DiagMask)) &&((userLevel & DiagMask) !=0)) || (((userLevel & PerfMask) <= (configLevel & PerfMask)) &&((userLevel & PerfMask) != 0))){ // do the trace}
A CPU evaluates the developer-configured and user-desired tracing levels in performing the comparison. First, the CPU would determine if each comparison in the parallel comparison results in a 0, which in the examples above, would be a no-operation (no-op) command. If the comparison results in a 0, then the trace is not performed. If the comparison does not result in a no-op, then the comparison determines if the user levels and the configuration (e.g., developer's) level match or overlap. If there is a match or overlap, then the trace will be performed for the matching level and every level above the matching level.
Writing program code for parallel comparisons using formats similar to the above IF statements would require a greater number of instructions than required for a single comparison. Additionally, more instructions would be required if more comparisons are to be completed simultaneously. That is, for example, if administrative or operation events are also traced, and are thus added in the parallel comparison examples above for diagnostic and performance traces, more instructions may be needed.
One way that a CPU performs the comparison of two variables to determine if a first variable is less than or equal to a second variable involves binary arithmetic. The first and second variables are represented to the CPU as binary numbers. If it is desired to know if X is less than Y, Y can be subtracted from X (i.e., X−Y), and if the result is a negative number, then X is less than Y. Using the example of a trace infrastructure, X may be thought of as the developer's configuration trace level, and Y as the user's desired trace level. It will be recalled that in the example tracing infrastructure, the trace will be performed for the matching level and every level above the matching level. Thus, if a developer's trace level subtracted from a user's trace level results in a sign change (i.e., a negative number), then one would presume a trace should be performed. The following examples show that this logic works some but not all of the time.
In a successful example, if the developer establishes a configuration level for performing a trace at level 3 and a user sets a corresponding trace level at 2, then because 3 minus 2 results in a positive number (i.e., 1), a trace would not be performed, as we would expect. Conversely, if the developer sets the trace level at 2 and a user sets the level at 3, then 2 minus 3 results in a negative number (i.e., −1), and therefore the trace would be performed, as we would expect.
Problems with the logic arise when a level is set at 0. For example, if a developer determines that a diagnostic trace of a particular function should never be performed, and thus sets the configuration level for the diagnostic trace at 0 (i.e., a no-op), and a user sets the configuration trace level at 4, then a subtraction results in a sign change, as 0 minus 4 is a negative number (i.e., −4). Because the developer determined that no diagnostic traces on the particular function should be performed, though, this result could lead to an incorrect result or an error.
It is understood that the problems herein described are not limited to tracing infrastructure and that there are similar problems associated with other comparison functions that would benefit from parallel comparisons. For example, parallel comparisons may be used in database systems where multiple operators check a user-provided input and select items from a database based on comparison of the input to a predetermined value.
Therefore, there is a need for systems and methods for performing parallel comparisons taking into account the manner in which a CPU performs arithmetic and without requiring a great increase in program code instructions.